package com.edu.boot301demo.exception;

import com.edu.boot301demo.common.R;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * 如果出现了异常：本类和全局都不能处理，
 * SpringMVC有兜底处理机制：自适应处理（浏览器返回页面，移动端响应Json）
 * 最佳实现：编写全局异常处理器，处理所有异常。
 * <p>
 * 前端关心异常状态，后端关心正确业务流程。
 * 推荐：后端只编写正确的业务逻辑，如果出现业务问题，后端通过抛异常的方式提前中断业务逻辑。前端感知异常。
 * <p>
 * 异常处理的最终方式：
 * 1.必须有业务异常类：继承Exception
 * 2.必须有异常枚举类1：枚举类中定义异常状态码和异常信息
 * 3.编写业务代码的时候，只需要编写正确逻辑，如果出现预期的问题，抛异常中断逻辑并通知上层。
 * 4.全局异常处理器：捕获异常，返回给前端一个错误信息。处理所有异常，返回给前端约定的Json数据与错误码。
 */
@ControllerAdvice //全局异常处理
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Map<String, String>> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        // bindingResult 中封装了所有错误信息
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            // 1. 获取错误属性名
            String field = fieldError.getField();
            // 2. 获取错误信息
            String message = fieldError.getDefaultMessage();
            errorMap.put(field, message);
        }
        return R.error("数据校验失败", 500, errorMap);
    }

    @ExceptionHandler(Exception.class)
    public R<String> error(Exception e) {
        e.printStackTrace();
        return R.error("其他异常:" + e.getMessage(), 500);
    }
}
